<?

//	*****************************************
//	SbSE site structure fetch component
//	v1.1.3 / 2011.12.12
//	*****************************************

class STRUCT {

	var $url;
	var $template;
	var $data;
	
	var $fullTree;
	var $filterOptions;
	
	var $res;
	
	function STRUCT() {

		$this->data = array();
		$this->res = 255;
		$this->id = 0;
		$this->template = '';
		$this->kind = -1;
		
		$this->fullTree = false;
		$this->allKeys = array();
		$this->str = array();
		
		$this->filterOptions = array();
	}
	
	function init($url, $lang = '') {

		$this->url = $url;
		$this->lang = $lang;

		list($this->fullTree, $this->allKeys) = $this->_getFullTree();

		$this->res = $this->fetch();
		
		return ! (bool) $this->res;
	}
	
	function _getChildren($c, $drillDown = false) {	// get 
		$res = array();
		$keys = array();
		
		foreach($this->str as $id => $v) {
			if ($v['parent'] == $c) {
				unset($this->str[$id]);
				$res[$id] = $v;
				$keys[] = $id;
			}
		}
		if ($drillDown)
			foreach($res as $id => $v) {
				list($cdata, $ckeys) = $this->_getChildren($id, $drillDown);
				$res[$id]['keys'] = $ckeys;
				$res[$id]['data'] = $cdata;
				$keys = array_merge($keys, $ckeys);
			}
		return array(sizeof($res) ? $res : false, $keys);
	}
	
	function _getFullTree() {
		if ($this->fullTree) return $this->fullTree;
		
		if (MC && ($t = mc('struct.fulltree.'.$this->lang)))
			return $t;	// got from Memcached

		if ($this->str = datafetch_array('db_list', array(
			'select' => 'struct.*, data.value as localname',
			'table' => tb('struct').' LEFT JOIN '.tb('data')." ON 
								(data.id_parent = struct.id) 
								AND (data.id_data=".D_PAGENAMES.") 
								AND ((data.assoc IS NULL) OR (data.assoc='') OR INSTR(data.assoc,'".$this->lang."')!=0) 
								AND (data.name='name')",
			'order' => 'pos', 'index' => 'id'))) {

			$t = $this->_getChildren(0, 1);

//			if (MC)
//				$x = $GLOBALS['mc']->set(MC_PREFIX.'struct.fulltree.'.$this->lang, $t, MC_EXPIRE - mt_rand(2*60, 7*60));
			mcSet('struct.fulltree.'.$this->lang, $t, MC_EXPIRE - mt_rand(2*60, 7*60));
			
//debug($x ? 'stored' : 'not stored');
//debug($GLOBALS['mc']->getResultMessage());
			return $t;
		}
			
		return false;
	}
	
	function getAliasById($pid, $lang = '') {			// return page alias by it's id in the STRUCT table
		if ($pid && in_array($pid, $this->allKeys)) {
			$path = '/'.$lang;
			$start = $this->fullTree;
			
			do {
				if (isset($start[$pid])) {
					if ($start[$pid]['keyword']) $path .= $start[$pid]['keyword'].'/';
					return $path;
				}
				
				$check = false;
				foreach($start as $id => $v)
					if (in_array($pid, $v['keys'])) {
						$check = $v['data'];
						if ($v['keyword']) $path .= $v['keyword'].'/';
						break;
					}

				$start = $check;
			} while($start);
		}
		
		return false;
	}

	function getPageById($pid, $lang = '') {			// return page alias by it's id in the STRUCT table
		if ($pid && in_array($pid, $this->allKeys)) {
			$start = $this->fullTree;
			
			do {
				if (isset($start[$pid])) {
					return $start[$pid];
				}
				
				$check = false;
				foreach($start as $id => $v)
					if (in_array($pid, $v['keys'])) {
						$check = $v['data'];
						break;
					}

				$start = $check;
			} while($start);
		}
		
		return false;
	}
	
	function _flatten($page) {
		$res = $page;
		unset($res['data']);
		return $res;
	}
	
	function parseUrl($url) {
		if (is_string($url)) {
			$temp = _parseURL($url);
			$url = $temp['url'];
		}

		$start = $this->fullTree;
		$res = array('data' => array());
//		$this->data = array();

		$next = $start;

		foreach($url as $u) {
			
			do {
				$start = $next;
				$next = false;
				
				if ($start) {
					foreach($start as $s) {
//debug($u, 'current u');						
//debug($s, 'start as s');						
						if ($s['keyword']) {
							if ($s['keyword'] == $u['path']) {
								$res['data'][] = array('struct' => $this->_flatten($s), 'path' => $u['path'], 'params' => $u['params']);
								$res['id'] = $s['id'];
								$res['kind'] = $s['kind'];
								$res['template'] = $s['template'];
								$next = $s['data'];
								break 2;
							}
						} else {			// no keywords for the main page...
							$res['data'][] = array('struct' => $this->_flatten($s), 'path' => '', 'params' => $u['params']);
							$res['id'] = $s['id'];
							$res['kind'] = $s['kind'];
							$res['template'] = $s['template'];
							$next = $s['data'];
							
							if ($u['path'] && !$u['virtual']) break; else break 2;	// end of process if nothing to be parsed
						}
					}
				}
				
				if (!$next) {
					$res['id'] = 0;
					$res['kind'] = PK_NOTFOUND;	//! 404 page not found - hardcoded in const.php
					$res['template'] = PK_NOTFOUND_TEMPLATE;
					return $res;
				}
				
			} while (1);
			
		}
		
		return $res;
	}

	function fetch() {
		$res = $this->parseUrl($this->url);
		
		$this->data = $res['data'];
		$this->id = $res['id'];
		$this->kind = $res['kind'];
		$this->template = $res['template'];
		return 0;
	}

	function filter($v) {
		return	($v['attr'] & $this->filterOptions['attr'] == $this->filterOptions['attr']) && 
					($v['tag'] & $this->filterOptions['tag'] == $this->filterOptions['tag']);
	}
	
	function getFilteredTree($o = array('attr' => 0, 'tag' => 0), $data = false) {
		if (!$data) $data = $this->fullTree;
		$this->filterOptions = $o;
		return $this->getFiltered($data);
	}

	function getFiltered($data = false) {
		if (!$data) $data = $this->fullTree;
		$res = $this->doFilter($data);

		foreach ($res as $k => $v)
			if ($v['data'])
				$res[$k]['data'] = $this->getFiltered($v['data']);

		return $res;
	}
	
	function doFilter($data = array()) {
		$res = array();
		if (is_array($data)) {
			foreach($data as $k => $v)
				if ($this->filter($v))
					$res[$k] = $v;
		}
		return array_mark_bounds($res);
	}

}
